#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/signal.h>
#include <execinfo.h>

#include <iostream>
#include <fstream>
#include <ostream>

#include "display.h"
#include <torrent/torrent.h>
#include <client/download.h>
#include <torrent/exceptions.h>
#include <algorithm>

Display* display = NULL;
bool shutdown = false;

void signal_handler(int signum) {
	void* stackPtrs[50];
	char** stackStrings;
	int stackSize;

	static bool called = false;

	switch (signum) {
	case SIGINT:
		std::cout << "Shuting down" << std::endl;

		shutdown = true;

		torrent::shutdown();

		return;

	case SIGSEGV:
		if (called) {
			exit(0);
		}

		called = true;

		// Print the stack and exit.
		stackSize = backtrace(stackPtrs, 50);
		stackStrings = backtrace_symbols(stackPtrs, stackSize);

		// Make sure we are in correct mode.
		delete display;
		display = NULL;

		std::cout << "Signal SEGFAULT received, dumping stack:" << std::endl;

		for (int i = 0;  i < stackSize; ++ i)
			std::cout << i << ' ' << stackStrings[i] << std::endl;

		exit(-1);

	default:
		break;
	}
}

int main(int argc, char **argv) {
	int fIndex = 0;
	fd_set rset, wset, eset;
	struct timeval timeout;

	std::ofstream log;

	signal(SIGINT, signal_handler);
	signal(SIGSEGV, signal_handler);

	try {

		torrent::initialize();

		for (fIndex = 1; fIndex < argc; ++fIndex) {
			std::fstream f(argv[fIndex], std::ios::in);

			if (!f.is_open())
				continue;

			torrent::DList::const_iterator dItr = torrent::create(f);

			torrent::start(dItr);
		}

		fIndex = 0;
		display = new Display();

		bool viewPeers = false;
		int64_t lastDraw = torrent::get(torrent::TIME_CURRENT) - (1 << 22);

		torrent::DList::const_iterator curDownload = torrent::downloads().end();

		Download download(curDownload);

		while (!shutdown) {
			if (lastDraw + 1000000 < torrent::get(torrent::TIME_CURRENT)) {
				lastDraw = torrent::get(torrent::TIME_CURRENT);

				if (viewPeers)
					download.draw();
				else
					display->drawDownloads(curDownload);
			}

			FD_ZERO(&rset);
			FD_ZERO(&wset);
			FD_ZERO(&eset);

			FD_SET(0, &rset);

			int64_t t = std::min(1000000 + lastDraw - torrent::get(torrent::TIME_CURRENT),
					torrent::get(torrent::TIME_SELECT));

			if (t < 0)
				t = 0;

			timeout.tv_sec = t / 1000000;
			timeout.tv_usec = t % 1000000;

			int n = std::max(1, torrent::mark(&rset, &wset, &eset));

			if (select(n + 1, &rset, &wset, &eset, &timeout) == -1)
				if (errno == EINTR)
					continue;
				else
					throw torrent::local_error("Error polling sockets");


		}

	} catch (const std::exception& e) {

	}

	return 0;
}



